﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using XCI.Core;
using XCI.Helper;

namespace XCI.Config
{
    /// <summary>
    /// Json配置实现类
    /// </summary>
    public class JsonConfigProvider : IConfigProvider
    {
        #region 私有字段

        private Dictionary<string, object> data;

        #endregion

        #region 构造函数

        /// <summary>
        /// 使用指定文件路径初始化Json配置实例,并自动加载文件数据
        /// </summary>
        /// <param name="path">文件路径(绝对路径或者http远程Url)</param>
        public JsonConfigProvider(string path)
        {
            Path = path;
            Load();
        }

        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置配置文件路径
        /// </summary>
        public string Path { get; }

        #endregion

        #region IConfigurationProvider成员

        /// <summary>
        /// 加载配置
        /// </summary>
        public void Load()
        {
            if (string.IsNullOrEmpty(Path))
            {
                throw new ArgumentException("请指定配置文件路径", nameof(Path));
            }
            if (string.IsNullOrEmpty(Path))
            {
                throw new ArgumentException("请指定配置文件路径", nameof(Path));
            }
            string json = string.Empty;
            if (Path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                WebApi webApi = new WebApi(TimeSpan.FromSeconds(5));
                json = webApi.Get(Path);
                DebugHelper.Debug($"从远程 {Path} 成功加载配置文件。");
            }
            else
            {
                if (File.Exists(Path))
                {
                    json = File.ReadAllText(Path, System.Text.Encoding.UTF8);
                    DebugHelper.Debug($"从本地 {Path} 成功加载配置文件。");
                }
                else
                {
                    DebugHelper.Debug($"未找到配置文件 {Path} ,无法加载。");
                }
            }

            if (!string.IsNullOrEmpty(json))
            {
                try
                {
                    data = JsonHelper.Deserialize<Dictionary<string, object>>(json);
                }
                catch (Exception e)
                {
                    DebugHelper.Catch($"加载配置文件失败,{e.Message}");
                    throw;
                }
            }
            if (data == null)
            {
                data = new Dictionary<string, object>();
            }
        }

        /// <summary>
        /// 保存配置
        /// </summary>
        public void Save()
        {
            if (Path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                DebugHelper.Debug($"远程配置文件 {Path} 无法保存。");
            }
            else
            {
                var settings = JsonHelper.GetDefaultSetting();
                settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
                settings.Formatting = Newtonsoft.Json.Formatting.Indented;
                JsonHelper.SerializeByPath(Path, data, settings);
                DebugHelper.Debug($"从本地配置文件保存成功 {Path}。");
            }
        }

        /// <summary>
        /// 获取指定名称的配置对象
        /// </summary>
        /// <typeparam name="T">配置类型</typeparam>
        /// <param name="key">配置名称</param>
        /// <param name="defaultValue">如果未找到指定名称的配置对象时,返回此默认值</param>
        /// <returns>返回指定名称的配置对象</returns>
        public T Get<T>(string key, Func<T> defaultValue = null) where T : class
        {
            if (data.TryGetValue(key, out var value))
            {
                var result = JsonHelper.ToObject<T>(value);
                data[key] = result;
                return result;
            }
            if (defaultValue == null) return default(T);

            T dafValue = defaultValue.Invoke();
            data[key] = dafValue;
            return dafValue;
        }

        /// <summary>
        /// 设置指定名称的配置对象
        /// </summary>
        /// <typeparam name="T">配置类型</typeparam>
        /// <param name="key">配置名称</param>
        /// <param name="value">配置对象</param>
        public void Set<T>(string key, T value) where T : class
        {
            data[key] = value;
        }

        /// <summary>
        /// 读取应用程序配置
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="defaultValue">如果找不到,返回的默认值</param>
        /// <returns>返回key对应的值,如果找不到key则返回指定的默认值</returns>
        public string GetAppSettings(string key, string defaultValue = "")
        {
            var dic = Get(R.AppSettingsName, () => new Dictionary<string, string>());
            return dic.TryGetValue(key, out string value) ? value : defaultValue;
        }

        /// <summary>
        /// 设置应用程序配置
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">键值</param>
        public void SetAppSettings(string key, string value)
        {
            var dic = Get(R.AppSettingsName, () => new Dictionary<string, string>());
            dic[key] = value;
        }

        #endregion
    }
}